Conversation
…utput (#78) Before: ci.yml and test.yml each did a full MSBuild restore + build (~4 min each) After: ci.yml builds + uploads artifacts, test.yml downloads and runs tests only Changes: - ci.yml: add build-output artifact upload (1-day retention) - ci.yml: add paths-ignore (skip on docs-only changes) - ci.yml: add concurrency (cancel in-progress on new push) - test.yml: trigger on workflow_run (waits for CI completion) - test.yml: download build-output instead of building - test.yml: no more restore/build steps - format.yml: only trigger when .cs/.vb/.editorconfig files change Saves ~4 min of Windows runner time per push by not building twice. All 3 workflows remain separate with their own status checks. Co-authored-by: RandomCrocodile <mawi@polosab.com>
CodeQL was still on windows-2022 (MSBuild 17) which can't resolve .NET 10 SDK from global.json. Also removed obsolete .NET 4.6.1 targeting pack install (net48 doesn't need it) and bumped checkout to v5.
- Issue template config: point discussions to our repo, add Ideas + General links
- CODEOWNERS: mkaring → mcpolo99
- FUNDING.yml: mkaring → mcpolo99
- MSBuild.Tasks PackageProjectUrl: point to our repo
- Test [Trait("Issue")] attributes kept as upstream attribution (historical)
…ents workflow_run doesn't associate with PRs reliably — test results and coverage comments were not posted on PR #79. Reverted to direct push/pull_request triggers with its own build step. Still optimized with: - paths-ignore (skip on docs-only changes) - concurrency (cancel in-progress on new push) - NuGet cache (shared cache key with ci.yml) - Removed build-output artifact from ci.yml (no longer needed)
…elop (#82) * chore: rename master→main, pre-release→develop, adopt GitHub branch conventions Branch renames: - master → main (default branch) - pre-release → develop (integration branch) All references updated: - ci.yml: triggers, release jobs, dev-release job (was pre-release) - test.yml, format.yml, codeql-analysis.yml: branch triggers - dependabot.yml: target branch - README.md: contributing section, CI badge - CONTRIBUTING.md: branch naming convention, PR target New branch naming convention (documented in CONTRIBUTING.md): - Issue-linked: {number}-{slug} via gh issue develop - Feature: feature/{description} - Chore: chore/{description} - Docs: docs/{description} - Hotfix: hotfix/{description} (from main) - Experiment: experiment/{description} * feat(ci): lightweight lint on push, full CI on PR only (#81) New workflow layout: - lint.yml (NEW): every push + PR — format + style + Roslyn analyzers without building. Posts results to PR comment or issue comment (parses issue number from branch name). ~2 min. - ci.yml: PR + main/develop push only — full build + package - test.yml: PR only — full build + test + coverage - codeql: weekly (Mon 3am, skips if no commits) + manual trigger - format.yml: DELETED — replaced by lint.yml Cost per event: - Feature branch push: ~2 min (was ~9 min) — 77% reduction - PR: ~11 min (lint + ci + test, unchanged) - Merge to main: ~5 min (ci only) - CodeQL: weekly conditional, not on every push/PR --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
# Conflicts: # .github/workflows/ci.yml # .github/workflows/codeql-analysis.yml # .github/workflows/test.yml # CONTRIBUTING.md
# Conflicts: # README.md
…Logging (#85) * refactor: extract IProgressReporter from ILogger (#64) Separate progress reporting (Progress, EndProgress, Finish) from logging into a new IProgressReporter interface. This is the first step toward replacing the custom ILogger with Microsoft.Extensions.Logging + Serilog. - Add IProgressReporter interface and NullProgressReporter - Remove Progress, EndProgress, Finish from ILogger and all implementations - Remove dead BeginModule/EndModule from NullLogger - Add ProgressReporter property to ConfuserParameters and ConfuserContext - Replace PackerLogger (full ILogger decorator) with PackerProgressReporter - Update all WithProgress call sites to use context.ProgressReporter - Fix MSBuildLogger.Finish bug (was setting HasError=false on failure) - Seal NullLogger class * feature: add M.E.L abstraction and MelLoggerAdapter (#64) Add Microsoft.Extensions.Logging.Abstractions to Confuser.Core (netstandard2.0 compatible) and a MelLoggerAdapter that bridges M.E.L ILogger to the internal Confuser.Core.ILogger interface. This allows callers to pass a standard M.E.L logger (backed by Serilog or any other provider) into ConfuserEngine without changing any internal code yet. * feature: replace CLI ConsoleLogger with Serilog (#64) Wire up Serilog as the logging provider in the CLI via Microsoft.Extensions.Logging and MelLoggerAdapter. - Add Serilog, Serilog.Extensions.Logging, Serilog.Sinks.Console - Delete custom ConsoleLogger — Serilog handles all console output - Add --verbose (-v, -vv, -vvv) and --quiet (-q) CLI flags - Default: Information level; -q: Warning; -v: Debug; -vv+: Verbose * feature: replace GUI logger with Serilog FlowDocument sink (#64) Wire up Serilog in the WPF GUI via a custom FlowDocumentSink that renders color-coded log output to the protection log panel. - Add Serilog and Serilog.Extensions.Logging to ConfuserEx - Create FlowDocumentSink — custom Serilog sink for WPF Paragraph - Remove ILogger from ProtectTabVM — now uses MelLoggerAdapter - ProtectTabVM keeps only IProgressReporter (progress bar + finish) - Delete ~40 lines of manual ILogger boilerplate * chore: add local-ci.sh script mirroring GitHub Actions pipeline Full local CI script that replicates lint.yml, ci.yml, and test.yml: - lint: whitespace, style, and analyzer checks via dotnet format - build: dotnet build for SDK projects + MSBuild.exe for C++/CLI - test: discovers all *.Test.csproj, runs with coverage, summary - package: creates CLI, GUI, and combined zip archives Usage: ./scripts/local-ci.sh [lint|build|test|package|all] * refactor: replace Confuser.Core.ILogger with Microsoft.Extensions.Logging.ILogger (#64) Complete migration from the custom 13-method ILogger interface to the standard M.E.L ILogger abstraction across all projects. - Change ConfuserContext.Logger and ConfuserParameters.Logger to M.E.L ILogger - Convert all ~80 call sites: Debug→LogDebug, Info→LogInformation, Warn→LogWarning, Error→LogError, *Exception→swap parameter order - Rewrite MSBuildLogger as MSBuildMelLogger implementing M.E.L ILogger - Rewrite XUnitLogger implementing M.E.L ILogger + IProgressReporter - Remove MelLoggerAdapter (no longer needed — M.E.L is the native type) - Delete Confuser.Core.ILogger, NullLogger (replaced by M.E.L NullLogger) - Add test-results/ and coverage/ to .gitignore * chore: fix import ordering to pass CI lint (#64) * fix: dispose GUI logger factory after async protection completes (#64) DoProtect used 'using var loggerFactory' which disposed the factory (and the Serilog logger via dispose:true) as soon as DoProtect returned. Since ConfuserEngine.Run executes asynchronously on a background thread, this disposed the logger before the protection actually used it, silently dropping log output mid-run. Move disposal into the ContinueWith continuation so the factory lives for the full protection lifetime. * test: fix flaky GUI protect test — deterministic tab navigation (#64) Gui_ProtectSampleApp_ShowsSuccess intermittently failed at the Protect! button lookup (~1 in 3 runs). Two root causes: 1. ByText("Protect!") ambiguously matched both the tab header and the Protect! button (they share the caption), so the wrong element could be clicked and the tab never actually got selected. 2. WPF virtualizes inactive tab content — the Protect! button does not enter the UIA tree until the tab is selected AND rendered. The 5s button-find timeout was too short under load. Fix: match the tab by TabItem control type + name, Select() it and wait for IsSelected, then find the button with a 15s timeout. 5/5 consecutive full-suite runs now pass 3/3 (previously ~1/3 failed). --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
* fix: make all test projects discoverable and green (#84) ~30 test projects were silently skipped by dotnet test — they lacked Microsoft.NET.Test.Sdk / xunit.runner.visualstudio, so discovery found 0 tests and exited 0. Making them run revealed several pre-existing failures the skip had hidden. This fixes discovery AND all exposed failures: 144 tests now run and pass (was 29 across 3 projects). Test infrastructure: - Add Microsoft.NET.Test.Sdk + xunit runner to Tests/Directory.Build.props for every *.Test project; remove the now-duplicate refs from the 3 projects that had them; trim the shared Confuser.UnitTest library to just xunit (it has no tests) - Copy Confuser.Runtime.dll (net20) next to every test binary — the protection pipeline needs it at obfuscation time - Move Coverlet coverage to Directory.Build.targets, enabled only for .NET (Core) test projects: Coverlet instruments the signed Confuser.* assemblies in-place, breaking their strong name, which .NET Framework refuses to load (net4x tests still run, just without coverage) Product robustness (analyzers must not crash on unresolvable BCL refs): - TypeBlobAnalyzer: skip external/unresolvable attribute and generic types instead of ResolveTypeDefThrow — they are never renamed anyway - ManifestResourceAnalyzer: build the GetManifestResourceStream(string) reference from the call's own signature when the BCL declaring type can't be resolved; unchanged when resolution succeeds Test brittleness (assert on stable data, not volatile obfuscated names): - MethodOverloading: assert original names are present in the symbols map values instead of looking up by hardcoded obfuscated keys - MessageDeobfuscation: verify the symbols map contains the expected originals and round-trips through the deobfuscator, instead of asserting exact obfuscated identifiers Fixes #84 * fix: drive test coverage via RunSettingsFilePath, not --collect (#84) Both local-ci.sh and the test.yml CI workflow forced --collect:"XPlat Code Coverage" on the command line for every test project. That flag overrides the per-project RunSettingsFilePath gate (Tests/Directory.Build.targets), forcing Coverlet to instrument the signed Confuser.* assemblies on net4x — which breaks their strong name so .NET Framework refuses to load them, failing every net4x test. Drop --collect and let RunSettingsFilePath enable coverage only for the .NET (Core) test projects. Coverage is still collected for the 5 Core assemblies; net4x projects run clean. Full local CI: 144 passed, 0 failed. * chore: skip Confuser.GUI.Test by default in local-ci (#84) Confuser.GUI.Test is a FlaUI smoke test that launches and drives the real ConfuserEx WPF window — it pops UI on screen and takes ~35s. Skip it by default for quiet local runs; set RUN_GUI_TESTS=1 to include it. It still runs in CI on the headless Windows runner. * chore: ignore release .zip packages (#84) The CI/local-ci package step produces ConfuserEx-CLI.zip, ConfuserEx-GUI.zip and ConfuserEx.zip in the repo root — ignore them so they aren't committed. --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
* chore: upgrade dnlib from 3.6.0 to 4.5.0 (#70) Evaluated and upgraded dnlib to the latest 4.x. The only breaking API change affecting ConfuserEx: dnlib 4.x added IChunk.CalculateAlignment(). Implemented it on the two custom chunk classes in the AntiTamper JIT mode (JITMethodBody, JITBodyIndex), returning 0 (default/no alignment) to preserve the pre-4.x behaviour. Evaluation notes: - netstandard2.0 target preserved (dnlib 4.5.0 still ships net35/net45/ netstandard2.0/net6.0) — Confuser.Core net48+netstandard2.0 unaffected - DnlibUtils extension methods compile unchanged - Resolve/ResolveThrow, ModuleWriter events, AssemblyResolver: no API changes affecting us - Full suite green: 144 passed, 0 failed (incl. AntiTamper, Compressor, packer, and all cross-framework obfuscation tests) Fixes #70 * perf: route HasAttribute through dnlib IsDefined; test ref-struct generics (#70) Two low-risk wins enabled by the dnlib 4.5 upgrade: - HasAttribute now calls CustomAttributeCollection.IsDefined(fullName) instead of a manual LINQ scan over CustomAttributes. This is the by-full-name lookup dnlib 4.2 optimized, and it benefits all 10 callers (including the per-definition renamer analysis path). Behaviour is identical — full suite stays green. - Add a regression test locking in that obfuscation preserves the 'allows ref struct' generic constraint (GenericParamAttributes. AllowByRefLike, named by dnlib 4.x). The net10 library subject now carries such a constraint, and Library_Net10_PreservesAllowByRefLike loads the obfuscated output and asserts the flag survives. ConfuserEx only renames generic parameters, so the attribute bits are preserved — this guards against a future change silently dropping them. 145 tests pass (was 144). --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
* feature: add DiagnosticCollector and report formatter (#65) Core of the diagnostic report collector: a DiagnosticCollector that decorates both ILogger and IProgressReporter, capturing a full-verbosity transcript, timing and outcome during an obfuscation run, plus a DiagnosticReport formatter that renders a self-contained markdown report. - Full-verbosity capture independent of display level; bounded ring buffer (last 2000 entries) with dropped-entry accounting. - Last-wins Finish so a packer's nested run does not clobber the top-level result/elapsed. - Redaction: never emits strong-name passwords; scrubs the user-profile path from config and log lines. Dynamic code-fence prevents markdown break-out. - 19 unit tests, TDD. * feature: add --dump diagnostic report flag to CLI (#65) Wraps the logger and progress reporter with a DiagnosticCollector when --dump is passed, and writes the markdown report after the run completes (success or failure). --dump uses a default filename; --dump=<file> writes to a custom path. The report path is printed to the console. E2E test asserts the report is written with the expected sections. * feature: add Copy Report button to GUI protect tab (#65) The protect tab now wraps the logger and progress reporter with a DiagnosticCollector during each run. A 'Copy Report' button (enabled once a run completes, success or failure) copies the markdown diagnostic report to the clipboard for pasting into a bug report. Clipboard failures are swallowed so a transient lock cannot crash the app. * feature: add best-effort target framework to diagnostic report (#65) Reads each input module's TargetFrameworkAttribute (via dnlib, from an in-memory copy so the file is never locked) and adds a 'Target Framework' line to the report's configuration section. Best-effort: silently omitted when a module is missing, not a valid assembly, or predates the attribute (net2.0-3.5). Verified end-to-end — a net8 library reports '.NETCoreApp,Version=v8.0'; a failing run on an invalid assembly still produces a clean FAILED report. 4 new tests. --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
* chore: auto-install reportgenerator and emit markdown coverage in local-ci The offline CI now installs the reportgenerator global tool on demand (mirroring .github/workflows/test.yml) instead of silently skipping the coverage report when it is absent. It also emits the same report types as CI — HTML, Cobertura, TextSummary and MarkdownSummaryGithub — so a local run produces SummaryGithub.md, the offline equivalent of the coverage summary CI posts to the PR. * chore: add opt-in PR coverage-comment posting to local-ci Since GitHub Actions minutes are limited, local-ci now produces the same coverage markdown as CI (SummaryGithub.md) and can optionally post it to a PR as a single sticky comment via the gh CLI, gated behind POST_COVERAGE_PR=<num>. It edits a prior marked comment instead of spamming, mirroring the CI sticky comment. Posting is opt-in and never runs unless the variable is set; all posting failures are warnings that never fail the pipeline. --------- Co-authored-by: RandomCrocodile <mawi@polosab.com>
GitHub Actions minutes are limited, so the cloud pipeline now runs the full build only where it is required: PRs into main and pushes to main. PRs into develop are validated locally with scripts/local-ci.sh and do not run the pipeline automatically. - ci.yml/test.yml/lint.yml: auto-run only for PRs into main (+ push to main for ci release). For develop PRs the jobs run only when an admin adds the run-ci label or dispatches manually; a job-level if guards this. - lint.yml: removed the any-branch push trigger that fired a lint run on every push. - Removed format.yml (dead: targeted non-existent master/pre-release branches; superseded by lint.yml). - docs/building.md: refreshed the stale CI/CD table to match. This change is workflow + docs only, nothing to build or test. [skip ci] Co-authored-by: RandomCrocodile <mawi@polosab.com>
Lint Results
|
) Releases are no longer cut automatically on every push to main. A dedicated release.yml handles them two ways, both minute-conscious: - Manual: workflow_dispatch builds, tags and publishes a GitHub Release from main on demand (with a force input to release even without new commits). - Monthly: a cron on the 1st runs a cheap Ubuntu check that compares main to the last v* tag and only spends the Windows build+publish when there are new commits. ci.yml is reduced to build validation: removed the push-to-main release job and the now-dead dev-release job (develop no longer triggers ci after the gating in #90), and dropped the push trigger. docs/building.md updated. This change is workflow + docs only, nothing to build or test. [skip ci] Co-authored-by: RandomCrocodile <mawi@polosab.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release merge of
developintomain. Brings 16 commits (75 files) accumulated since the last release.Use a merge commit — NOT squash (project convention: keep develop/main history aligned).
Included since last release
--dumpCLI flag, GUI "Copy Report", redaction)local-ci.shRelease note (Actions currently disabled)
GitHub Actions are disabled (minutes overflow), so merging this will not auto-cut a release — no build/package/tag/publish will run. To release once minutes reset:
mainhas the newci.ymlwithworkflow_dispatch— trigger it manually from the Actions tab to build/package/publish (the merge push won't retro-trigger).Alternatively, re-enable Actions before merging so the merge push to
maintriggers the release automatically (costs the full build minutes).Validation
All work was validated locally via
scripts/local-ci.sh(full build + test + coverage, all green) on develop.